﻿@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Components.Forms

<EditForm EditContext="@editContext" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />

    <p class="name">
        Name: <InputText @bind-Value="person.Name" placeholder="Enter your name" />
    </p>
    <p class="email">
        Email: <InputText @bind-Value="person.Email" />
        <ValidationMessage For="@(() => person.Email)" />
    </p>
    <p class="confirm-email">
        Email: <InputText @bind-Value="person.ConfirmEmail" />
        <ValidationMessage For="@(() => person.ConfirmEmail)" />
    </p>
    <p class="age">
        Age (years): <InputNumber @bind-Value="person.AgeInYears" placeholder="Enter your age" />
    </p>
    <p class="height">
        Height (optional): <InputNumber @bind-Value="person.OptionalHeight" />
    </p>
    <p class="description">
        Description: <InputTextArea @bind-Value="person.Description" placeholder="Tell us about yourself" />
    </p>
    <p class="renewal-date">
        Renewal date: <InputDate @bind-Value="person.RenewalDate" placeholder="Enter the date" />
    </p>
    <p class="expiry-date">
        Expiry date (optional): <InputDate @bind-Value="person.OptionalExpiryDate" />
    </p>
    <p class="ticket-class">
        Ticket class:
        <InputSelect @bind-Value="person.TicketClass" size="4">
            <option>(select)</option>
            <option value="@TicketClass.Economy">Economy class</option>
            <option value="@TicketClass.Premium">Premium class</option>
            <option value="@TicketClass.First">First class</option>
        </InputSelect>
        <span id="selected-ticket-class">@person.TicketClass</span>
    </p>
    <p class="airline">
        <InputRadioGroup @bind-Value="person.Airline">
            Airline:
            <br>
            @foreach (var airline in (Airline[])Enum.GetValues(typeof(Airline)))
            {
                <InputRadio Value="airline" extra="additional" />
                @airline.ToString();
                <br>
            }
        </InputRadioGroup>
    </p>
    <p class="nested-radio-group">
        Pick one color and one country:
        <InputRadioGroup Name="country" @bind-Value="person.Country">
            <InputRadioGroup Name="color" @bind-Value="person.FavoriteColor">
                <InputRadio Name="color" Value="Color.Red" />red<br>
                <InputRadio Name="country" Value="Country.Japan" />japan<br>
                <InputRadio Name="color" Value="Color.Green" />green<br>
                <InputRadio Name="country" Value="Country.Yemen" />yemen<br>
                <InputRadio Name="color" Value="Color.Blue" />blue<br>
                <InputRadio Name="country" Value="Country.Latvia" />latvia<br>
                <InputRadio Name="color" Value="Color.Orange" />orange<br>
            </InputRadioGroup>
        </InputRadioGroup>
    </p>
    <p class="socks">
        Socks color: <InputText @bind-Value="person.SocksColor" />
    </p>
    <p class="accepts-terms">
        Accepts terms: <InputCheckbox @bind-Value="person.AcceptsTerms" title="You have to check this" />
    </p>
    <p class="is-evil">
        Is evil: <InputCheckbox @bind-Value="person.IsEvil" />
    </p>
    <p class="username">
        Username (optional): <InputText @bind-Value="person.Username" />
        <button type="button" @onclick="@TriggerAsyncValidationError">Trigger async error</button>
    </p>

    <button type="submit">Submit</button>

    <p class="model-errors">
        <ValidationSummary Model="person" />
    </p>

    <ValidationSummary />
</EditForm>

<ul>@foreach (var entry in submissionLog) { <li>@entry</li> }</ul>

@code {
    protected virtual bool UseExperimentalValidator => false;

    Person person = new Person();
    EditContext editContext;
    ValidationMessageStore customValidationMessageStore;

    protected override void OnInitialized()
    {
        editContext = new EditContext(person);
        editContext.SetFieldCssClassProvider(new CustomFieldCssClassProvider());
        customValidationMessageStore = new ValidationMessageStore(editContext);
    }

    // Usually this would be in a different file
    class Person
    {
        [Required(ErrorMessage = "Enter a name"), StringLength(10, ErrorMessage = "That name is too long")]
        public string Name { get; set; }

        [EmailAddress(ErrorMessage = "That doesn't look like a real email address")]
        [StringLength(10, ErrorMessage = "We only accept very short email addresses (max 10 chars)")]
        public string Email { get; set; }

        [Compare(nameof(Email), ErrorMessage = "Email and confirm email do not match.")]
        public string ConfirmEmail { get; set; }

        [Range(0, 200, ErrorMessage = "Nobody is that old")]
        public int AgeInYears { get; set; }

        public float? OptionalHeight { get; set; }

        public DateTime RenewalDate { get; set; } = DateTime.Now;

        public DateTimeOffset? OptionalExpiryDate { get; set; }

        [Required, Range(typeof(bool), "true", "true", ErrorMessage = "Must accept terms")]
        public bool AcceptsTerms { get; set; }

        [Required, Range(typeof(bool), "false", "false", ErrorMessage = "Must not be evil")]
        public bool IsEvil { get; set; } = true;

        [Required, StringLength(20, ErrorMessage = "Description is max 20 chars")]
        public string Description { get; set; }

        [Required, EnumDataType(typeof(TicketClass))]
        public TicketClass TicketClass { get; set; }

        [Required]
        [Range(typeof(Airline), nameof(Airline.BestAirline), nameof(Airline.NoNameAirline), ErrorMessage = "Pick a valid airline.")]
        public Airline Airline { get; set; } = Airline.Unknown;

        [Required, EnumDataType(typeof(Color))]
        public Color? FavoriteColor { get; set; } = null;

        [Required, EnumDataType(typeof(Country))]
        public Country? Country { get; set; } = null;

        [Required, StringLength(10), CustomValidationClassName(Valid = "valid-socks", Invalid = "invalid-socks")]
        public string SocksColor { get; set; }

        public string Username { get; set; }
    }

    enum TicketClass { Economy, Premium, First }

    enum Airline { BestAirline, CoolAirline, NoNameAirline, Unknown }

    enum Color { Red, Green, Blue, Orange }

    enum Country { Japan, Yemen, Latvia }

    List<string> submissionLog = new List<string>(); // So we can assert about the callbacks

    void HandleValidSubmit()
    {
        submissionLog.Add("OnValidSubmit");
    }

    void TriggerAsyncValidationError()
    {
        customValidationMessageStore.Clear();

        // Note that this method returns void, so the renderer doesn't react to
        // its async flow by default. This is to simulate some external system
        // implementing async validation.
        Task.Run(async () =>
        {
            // The duration of the delay doesn't matter to the test, as long as it's not
            // so long that we time out. Picking a value that's long enough for humans
            // to observe the asynchrony too.
            await Task.Delay(500);
            customValidationMessageStore.Add(editContext.Field(nameof(Person.Username)), "This is invalid, asynchronously");
            _ = InvokeAsync(editContext.NotifyValidationStateChanged);
        });
    }
}
